package cn.tqfeiyang.springplus.generator.engine;

import cn.tqfeiyang.springplus.generator.config.GeneratorConfig;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import cn.tqfeiyang.springplus.generator.jdbc.TableInfo;
import cn.tqfeiyang.springplus.generator.name.NameConverter;
import cn.tqfeiyang.springplus.generator.name.NameFormat;
import cn.tqfeiyang.springplus.generator.util.FileUtils;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 模板引擎抽象类
 *
 */
public abstract class TemplateEngine {

    private static final Logger LOGGER = LoggerFactory.getLogger(TemplateEngine.class);

    @Getter
    protected GeneratorConfig generatorConfig;

    public TemplateEngine(GeneratorConfig generatorConfig) {
        this.generatorConfig = generatorConfig;
    }

    protected abstract void merge(String templateName, Map<String, Object> objectMap, File outputFile) throws Exception;

    protected void merge(String templateName, Map<String, Object> objectMap, File outputFile, boolean fileOverride) {
        if (outputFile.exists()) {
            if (!fileOverride) {
                LOGGER.warn("跳过文件 [{}]", outputFile);
                return;
            } else {
                LOGGER.warn("覆盖文件 [{}]", outputFile);
            }
        }
        try {
            boolean exist = outputFile.exists();
            if (!exist) {
                File parentFile = outputFile.getParentFile();
                FileUtils.forceMkdir(parentFile);
            }
            merge(templateName, objectMap, outputFile);
        } catch (Exception exception) {
            throw new RuntimeException(exception);
        }
    }

    public void writeToFile(String templateName, Map<String, Object> objectMap, String outputFile, boolean fileOverride) {
        merge(templateName, objectMap, convertToAbsolutePath(outputFile), fileOverride);
    }

    public void writeToFile(String templateName, Map<String, Object> objectMap, NameFormat nameFormat, boolean fileOverride) {
        merge(templateName, objectMap, entityOutputFile(objectMap, nameFormat), fileOverride);
    }

    public void writeToFile(String templateName, TableInfo tableInfo, String outputFile, boolean fileOverride) {
        merge(templateName, getObjectMap(tableInfo), convertToAbsolutePath(outputFile), fileOverride);
    }

    public void writeToFile(String templateName, TableInfo tableInfo, NameFormat nameFormat, boolean fileOverride) {
        merge(templateName, getObjectMap(tableInfo), entityOutputFile(tableInfo, nameFormat), fileOverride);
    }

    private File entityOutputFile(TableInfo tableInfo, NameFormat nameFormat) {
        String outputFile = generatorConfig.getNameConverter().convert(tableInfo, nameFormat);
        return convertToAbsolutePath(outputFile);
    }

    private File entityOutputFile(Map<String, Object> objectMap, NameFormat nameFormat) {
        Object entityObject = objectMap.get("entity");
        if (entityObject != null && entityObject instanceof Map) {
            NameConverter nameConverter = generatorConfig.getNameConverter();
            String key = nameConverter.camelName(nameFormat.name());
            Object value = ((Map) entityObject).get(key);
            if (value != null) {
                return convertToAbsolutePath(StringUtils.toStringTrim(value));
            }
        }
        throw new RuntimeException("不能获取输出文件名");
    }

    private File convertToAbsolutePath(String file) {
        if (FileUtils.isAbsolutePath(file)) {
            return new File(file);
        }
        return FileUtils.combine(generatorConfig.getOutputDir(), file);
    }

    /**
     * 渲染对象 MAP 信息
     */
    public Map<String, Object> getObjectMap(TableInfo tableInfo) {
        Map<String, Object> objectMap = new HashMap<>();
        objectMap.put("author", generatorConfig.getAuthor());
        objectMap.put("email", generatorConfig.getEmail());
        objectMap.put("wechat", generatorConfig.getWechat());
        objectMap.put("phone", generatorConfig.getPhone());
        objectMap.put("date", new SimpleDateFormat(generatorConfig.getCommentDateFormat()).format(new Date()));
        objectMap.put("config", generatorConfig);
        objectMap.put("table", tableInfo);
        return objectMap;
    }
}